package com.xfcycle.zebrabikegp.util;

import org.apache.commons.codec.binary.Base64;

import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.List;

import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

/**
 * 对字符串进行加密处理工具类
 * Created by xFcycle on 2017/5/8.
 */

public class EncryptStringUtil {

    private static MessageDigest md5 = null;

    /**
     * 将数据转化为HmacSHA1格式字符串
     *
     * @param data
     * @param key
     * @return
     */
    public static byte[] String2HmacSHA1(String data, String key) {
        try {
            Mac mac = Mac.getInstance("HmacSHA1");
            //设置加密算法及加密密钥
            SecretKey secret = new SecretKeySpec(key.getBytes("UTF-8"), "HmacSHA1");
            mac.init(secret);
            return mac.doFinal(data.getBytes("UTF-8"));
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 将数据转化为Base64格式字符串
     *
     * @param argo 需要传递的byte数组
     * @return 返回转化成功的字符串
     * @throws UnsupportedEncodingException
     */
    public static String String2Base64(byte[] argo) throws UnsupportedEncodingException {
        try {
            byte[] encodeBase64 = Base64.encodeBase64(argo);
            return new String(encodeBase64);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 用于获取一个String的md5值
     *
     * @param str 需要加密的字符串
     * @return 转化完成的字符串
     */
    public static String getMd5(String str) {

        try {
            md5 = MessageDigest.getInstance("MD5");
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }

        byte[] bs = md5.digest(str.getBytes());
        StringBuilder sb = new StringBuilder(40);
        for (byte x : bs) {
            if ((x & 0xff) >> 4 == 0) {
                sb.append("0").append(Integer.toHexString(x & 0xff));
            } else {
                sb.append(Integer.toHexString(x & 0xff));
            }
        }
        return sb.toString();
    }


    private static char[] base64CharTable = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
            'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
            'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4',
            '5', '6', '7', '8', '9', '+', '/'};

    /**
     * 自定义Base64加密 仅限于传递蓝牙Ble校验
     *
     * @param originalStr 原始字符串
     * @return 加密后的校验字符串
     */
    public static String customBase64EncodeWithSalt(String originalStr, String auth_key) {

        //计算认证密码
        char[] chars = originalStr.toCharArray();
        StringBuilder strHex = new StringBuilder();
        //将密码地址转换为16进制字符串
        for (char c : chars) {
            strHex.append(Integer.toHexString((byte) c));
        }

        BigInteger biMacAddress = new BigInteger(strHex.toString(), 16);
        BigInteger biAuthKey = new BigInteger(auth_key, 16);

        //将车蓝牙的mac地址和key进行异或处理
        String strXor = biMacAddress.xor(biAuthKey).toString(16);
        StringBuilder sbXor = new StringBuilder();
        //将结果转化为16进制字符串，若长度不够8位前面自动用0补全
        for (int i = 0; i < strXor.length(); i = i + 2) {
            //TODO:可能出现数组下标越界
            String strBin = Integer.toBinaryString(Integer.parseInt(i + 2 <= strXor.length() ? strXor.substring(i, i + 2) : strXor.substring(i), 16));
            int j = 8 - strBin.length();
            for (int k = 0; k < j; k++) {
                sbXor.append("0");
            }
            sbXor.append(strBin);
        }

        //以6个字符为一组对字符串进行拆分 并将其转化为相应的单个字符
        StringBuilder authCode = new StringBuilder();
        for (int m = 0; m < sbXor.length(); m = m + 6) {
            if (m + 6 <= sbXor.length()) {
                String s = sbXor.substring(m, m + 6);
                if (s.length() == 6) {
                    authCode.append(base64CharTable[Integer.parseInt(s, 2)]);
                }
                continue;
            }
            String s1 = sbXor.substring(m);
            int p = 6 - s1.length();
            for (int j = 0; j < p; j++) {
                s1 = s1 + "0";
            }
            authCode.append(base64CharTable[Integer.parseInt(s1, 2)]);
        }
        //判断转化后的字符串是否为4的整数，不是则用 "=" 在字符串末尾填充
        int o = 4 - authCode.length() % 4;

        if (4 != o) {
            for (int n = 0; n < o; n++) {
                authCode.append("=");
            }
        }

        return authCode.toString();
    }

    /**
     * 自定义Base64解密 仅限于将车名中的base64加密字符串解析成原始地址 该原始地址为16进制数字组成的字符串
     *
     * @param originalStr 原始字符串
     * @return 加密后的校验字符串
     */
    public static String customBase64Decode(String originalStr) {
        List<String> macAddressList = new ArrayList<>();
        StringBuilder sb = new StringBuilder();

        //将原字符串每个字符与Base64字符表进行比对，将得到的位置转化为二进制数，并用0将其填充为长度为6的字符串
        char[] chars = originalStr.toCharArray();
        for (int i = 0; i < chars.length; i++) {
            for (int j = 0; j < base64CharTable.length; j++) {
                if (base64CharTable[j] == chars[i]) {
                    String binary = Integer.toBinaryString(j);
                    int k = 6 - binary.length();
                    for (int m = 0; m < k; m++) {
                        sb.append("0");
                    }
                    sb.append(binary);
                }
            }
        }

        StringBuilder macAddress = new StringBuilder();

        //将二进制字符串以8位为一串进行拆封并将其转化为16进制数字
        for (int n = 0; n < sb.length(); n = n + 8) {
            String hexStr = Integer.toHexString(Integer.parseInt(sb.substring(n, n + 8), 2)) + "";
            int o = 2 - hexStr.length();
            for (int p = 0; p < o; p++) {
                hexStr = "0" + hexStr;
            }
            macAddressList.add(hexStr + ":");
        }
        //这里得到的地址是反的，需要调换位置 FB:75 => 75:FB
        for (int p = macAddressList.size() - 1; p >= 0; p--) {
            macAddress.append(macAddressList.get(p));
        }
        return macAddress.substring(0, macAddress.length() - 1).toString().toUpperCase();
    }

    /**
     * 自定义Base64加密 将获得的设备地址用base64加密
     *
     * @param originalStr 原始字符串
     * @return 加密后的校验字符串
     */
    public static String customBase64Encode(String originalStr) {
        List<String> macAddressList = new ArrayList<>();
        StringBuilder sb = new StringBuilder();

        String[] singleStr = originalStr.split(":");
        StringBuilder oriSb = new StringBuilder();

        for (int index = 0; index < singleStr.length; index++) {
            String binaryStr = Integer.toBinaryString(Integer.valueOf(singleStr[index], 16));
            //二进制不足8位在前面加零
            int k = 8 - binaryStr.length();
            for (int m = 0; m < k; m++) {
                oriSb.append("0");
            }
            oriSb.append(binaryStr);
        }

        StringBuilder resultSb = new StringBuilder();
        //以6个字符为一组对字符串进行拆分 并将其转化为相应的单个字符
        for (int m = 0; m < oriSb.length(); m = m + 6) {
            //要截取的范围在字符串内
            if (m + 6 <= oriSb.length()) {
                String s = oriSb.substring(m, m + 6);
                if (s.length() == 6) {
                    resultSb.append(base64CharTable[Integer.parseInt(s, 2)]);
                }
                continue;
            }
            //截取的范围超过字符串
            String s1 = oriSb.substring(m);
            int p = 6 - s1.length();
            for (int j = 0; j < p; j++) {
                s1 = s1 + "0";
            }
            resultSb.append(base64CharTable[Integer.parseInt(s1, 2)]);
        }
        //判断转化后的字符串是否为4的整数，不是则用 "=" 在字符串末尾填充
        int o = 4 - resultSb.length() % 4;

        if (4 != o) {
            for (int n = 0; n < o; n++) {
                resultSb.append("=");
            }
        }

        return resultSb.toString();
    }
}
